﻿using System.Collections;
using UnityEngine;
using DG.Tweening;

public abstract class IInfoPanel:MonoBehaviour
{
    private ShowInfoPanel System;
    private RectTransform canvasRect;
    private RectTransform rect;
    public IInfoPanel prePanel { get; set; }
    public IInfoPanel nxtPanel { get; set; }
    protected float moveOutDistance;//移开视线需要的距离
    protected float delayDistanceNxt;//调用下一个移动前要延迟的距离
    protected float delayDistancePre;//调用上一个移动前要延迟的距离
    /// <summary>
    /// 当前panel是位于第几个显示的索引上的？用于告诉panel什么时候应当停止对nxt/pre进行滑动
    /// </summary>
    protected int panelIndex;
    /// <summary>
    /// 上一个依附点,依附点就是不超出依附索引范围都不会动的,如RoleIconpanel
    /// </summary>
    protected int preAttachIndex;
    /// <summary>
    /// 下一个依附点,依附点就是不超出依附索引范围都不会动的,如RoleIconpanel
    /// </summary>
    protected int nxtAttachIndex;
    /// <summary>
    /// 是否到达显示区域
    /// </summary>
    protected bool isShowInPanel;

    public virtual void Init(ShowInfoPanel system)
    {
        System = system;

        rect = transform as RectTransform;
        canvasRect = FindObj.FindObject("Canvas") as RectTransform;
        //Canvas的一半+自生的一半完=全移出去
        moveOutDistance = canvasRect.rect.height / 2 + rect.rect.height / 2;
        nxtAttachIndex = preAttachIndex = -1;//默认没有依附对象,如果有需要到子类赋值
    }

    /// <summary>
    /// 当UI面板关闭则调用此方法重置UIpanel显示为默认状态
    /// </summary>
    public void ResetScroll()
    { 
        if (preAttachIndex != -1 && panelIndex >= preAttachIndex)/*这里的>=很重要，只有=才能将最后依附索引对应的panel的滑动方法调用到*/
        {
            if (System.currentIndex <= nxtAttachIndex)//如果已经显示了则进行这个操作
            {
                ResetAndExChange();
                return;
            }
            else
            {
                System.currentIndex = panelIndex;
                rect.anchoredPosition = new Vector2(rect.anchoredPosition.x, 0);
                ResetAndExChange(); 
            }
        }
        //这里的等号很关键必须要，考虑到当依附对象显示时依附对象会提前调用curindex = panel到这儿就是等于了
        //为了本来就是这个panelIndex的普通panel能够显示，所以这里是>=
        if (System.currentIndex >= panelIndex)
        {
            System.currentIndex = panelIndex;
            rect.anchoredPosition = new Vector2(rect.anchoredPosition.x, 0);
        }         
        //控制下一个panel的到显示位置的逻辑
        if (prePanel != null && System.targetIndex != panelIndex /*|| prePanel.panelIndex == panelIndex*/)
        {//移除显示位置
            rect.anchoredPosition = new Vector2(rect.anchoredPosition.x ,- moveOutDistance);
            prePanel.ResetScroll(); 
        }
    }
    void ResetAndExChange()
    {
        if (prePanel.prePanel == null)
        {
            prePanel.ResetScroll();
            return;
        }
        prePanel.nxtPanel = nxtPanel;
        nxtPanel.prePanel = prePanel;

        panelIndex--;
        prePanel.ResetScroll();

        prePanel = prePanel.prePanel;
        prePanel.nxtPanel = this;
        nxtPanel = nxtPanel.prePanel;
        nxtPanel.prePanel = this;
    }
    /// <summary>
    /// 滑动显示下方的panel
    /// </summary>
    public virtual void ScrollNxt()
    {
        StartCoroutine(ScrollNxtCor());
    }
    IEnumerator ScrollNxtCor()
    {
        isShowInPanel = false;
        //当前移动到目标位置
        //1.首先判断是否到达了向下最大依附位置,对于有依附的panel来说panelIndex是需要变换的
        if (nxtAttachIndex != -1 && panelIndex < nxtAttachIndex) 
        {//说明当前依附面板正处于显示状态
            if (System.currentIndex >= preAttachIndex)
            {
                //如果当前显示的面板没有到达向下最大依附位置
                //只有交换位置了下一次才能调用到这个面板，进行循环操作毕竟每次输入每个节点都只调用一次
                MoveAndExChangeNxt();
                yield break;
            }
            else
            {
                System.currentIndex = panelIndex;
                rect.DOAnchorPosY(0, 0.5f).SetEase(Ease.OutExpo);
                while (true)
                {
                    if (rect.anchoredPosition.y >= delayDistanceNxt)
                    {
                        MoveAndExChangeNxt();
                        yield break;
                    }
                    yield return 0;
                }
            }
        }

        //2.判断当前正在显示的索引是否大于自身的索引(考虑到隐藏在上方的panel会被重复调用所以增加这个if)
        //如果大说明不做移动到窗口的操作直接移动下一个
        if (System.currentIndex <= panelIndex)
        {
            //2-1当前窗口移动到显示位置 
            System.currentIndex = panelIndex;
            rect.DOAnchorPosY(0, 0.5f).SetEase(Ease.OutExpo);
        }

        //3.移动下一个的逻辑 
        //如果当前显示窗口的位置不是目标索引位置则接着调用下一个panel                         说明有依附对象那么将两个panel一起滑动出来
        if (nxtPanel != null && System.targetIndex != panelIndex/*System.current不行?*//*|| nxtPanel .panelIndex==panelIndex*/)
        {//当前panel移出显示位置
            rect.DOAnchorPosY(moveOutDistance, 0.5f).SetEase(Ease.OutExpo);
            while (true)
            {
                //控制移动下一个panel
                if (rect.anchoredPosition.y >= delayDistanceNxt)
                {
                    nxtPanel.ScrollNxt();
                    break;
                }
                yield return 0;
            }
        }
    }
    void MoveAndExChangeNxt()
    {
        if (nxtPanel.nxtPanel == null)
        {
            nxtPanel.ScrollNxt();
            return;
        }
        nxtPanel.prePanel = prePanel;
        prePanel.nxtPanel = nxtPanel;

        panelIndex++;
        nxtPanel.ScrollNxt();//目前nxtPanel仍是初始化的值

        nxtPanel = nxtPanel.nxtPanel;
        nxtPanel.prePanel = this;
        prePanel = prePanel.nxtPanel;
        prePanel.nxtPanel = this;
    }
    /// <summary>
    /// 滑动显示上方的panel
    /// </summary>
    public virtual void ScrollPre()
    {
        StartCoroutine(ScrollPreCor());
    }
    IEnumerator ScrollPreCor()
    {//isShowInPanel = false;
        //上一个显示的panel的索引如果>向下最大依附是不行的
        //因为要依附的panel都没显示不能执行操作要<才行
        if (preAttachIndex != -1 && panelIndex >= preAttachIndex)/*这里的>=很重要，只有=才能将最后依附索引对应的panel的滑动方法调用到*/
        {
            if (System.currentIndex <= nxtAttachIndex)//如果已经显示了则进行这个操作
            {
                MoveAndExChangePre();
                yield break;
            }
            else
            {
                System.currentIndex = panelIndex;
                rect.DOAnchorPosY(0, 0.5f).SetEase(Ease.OutExpo);
                while (true)
                {
                    if (rect.anchoredPosition.y <= delayDistancePre)
                    {
                        MoveAndExChangePre();
                        yield break;
                    }
                    yield return 0;
                }
            }
        }

        //这里的等号很关键必须要，考虑到当依附对象显示时依附对象会提前调用curindex = panel到这儿就是等于了
        //为了本来就是这个panelIndex的普通panel能够显示，所以这里是>=
        if (System.currentIndex >= panelIndex )
        {
            System.currentIndex = panelIndex;
            rect.DOAnchorPosY(0, 0.5f).SetEase(Ease.OutExpo);
        }

        //控制下一个panel的到显示位置的逻辑
        if (prePanel != null && System.targetIndex != panelIndex /*|| prePanel.panelIndex == panelIndex*/) 
        {//移除显示位置
            rect.DOAnchorPosY(-moveOutDistance, 0.5f).SetEase(Ease.OutExpo);

            while (true)
            {
                if (rect.anchoredPosition.y <= delayDistancePre)
                {
                    prePanel.ScrollPre();
                    break;
                }
                yield return 0;
            }
        }
    }
    /// <summary>
    /// 移动前一个节点并与前一个节点的pre交换位置
    /// </summary>
    void MoveAndExChangePre()
    {//考虑到因为最后panelindex等于了依附index都还要执行一次交换，如果这个时候列表已经到第一个了在网上没有panel了所以要做这个判断
        if (prePanel.prePanel == null)
        {
            prePanel.ScrollPre();
            return;
        }
        prePanel.nxtPanel = nxtPanel;
        nxtPanel.prePanel = prePanel;

        panelIndex--;
        prePanel.ScrollPre();

        prePanel = prePanel.prePanel;
        prePanel.nxtPanel = this;
        nxtPanel = nxtPanel.prePanel;
        nxtPanel.prePanel = this;
    }
    public abstract void SetInfo(string roleName);
    public abstract void ClearInfo();

    protected abstract void InitInfo();
}